using System;
using System.Collections;
using System.IO;
using System.Threading;
using System.Windows.Forms;
using Slaks.DocumentSerialization.Document;
using Slaks.DocumentSerialization.ParsedFiles;
using Slaks.Graphs;
using Slaks.Graphs.Algorithms;
using Slaks.Graphs.GraphBuilder;
using Slaks.Graphs.GraphBuilder.Slaks;
using Slaks.Graphs.Algorithms.DistanceAlgorithm;

namespace SchenkerGraphsCommonality
{
	/// <summary>
	/// Summary description for ProcessMediator.
	/// </summary>
	public class ProcessMediator
	{
		private ProgressBar m_interFileProgress;
		private ProgressBar m_intraFileProgress;
		private string m_parsedFileList;
		private string m_outputDir;
		private int m_graphSize;
		private bool m_isOnlyOneFile;
		private string m_onlyOneFileName;
		private BuilderType m_graphRepresentation;
		private bool m_isHoldPreviousSeriesParsed;
		private static IList m_documentList = null;
		static ProcessMediator()
		{
			GraphBuilderFactory.Instance.AddGraphBuilder(BuilderType.StandardRepresentationSlaks,new StandardRepresentationSlaks());
			GraphBuilderFactory.Instance.AddGraphBuilder(BuilderType.RawFrequencyRepresentationSlaks,new RawFrequencyRepresentationSlaks());
			GraphBuilderFactory.Instance.AddGraphBuilder(BuilderType.NormalizedFrequencyRepresentationSlaks,new NormalizedFrequencyRepresentationSlaks());
		}
		public ProcessMediator(ProgressBar interFileProgress,
													 ProgressBar intraFileProgress,string parsedFileList,string outputDir,int graphSize,bool isOnlyOneFile,string onlyOneFileName,
			                     BuilderType graphRepresentation,bool isHoldPreviousSeriesParsed)
		{
			m_interFileProgress = interFileProgress;
			m_intraFileProgress = intraFileProgress;
			m_parsedFileList = parsedFileList;
			m_outputDir = outputDir;
			m_graphSize = graphSize;
			m_isOnlyOneFile = isOnlyOneFile;
			m_onlyOneFileName = onlyOneFileName;
			m_graphRepresentation = graphRepresentation;
			m_isHoldPreviousSeriesParsed = isHoldPreviousSeriesParsed;
		}

		public void Start()
		{
			Thread thread  = new Thread(new ThreadStart(StartProcess));
			thread.IsBackground = true;
			thread.Start();
		}
		private void StartProcess()
		{
			try
			{
				IList files = ParsedFiles.ReadXml(m_parsedFileList);
				m_interFileProgress.Maximum = files.Count;
				m_interFileProgress.Minimum = 0;

				m_intraFileProgress.Maximum = files.Count;
				m_intraFileProgress.Minimum = 0;

				int indexIntra = 0;
				if (m_documentList == null || m_isHoldPreviousSeriesParsed == false)
				{
					m_documentList = new ArrayList(files.Count);
						foreach (string file in files)
						{
							m_documentList.Add(Xml2Document.ReadXml(file));
							this.SetIntraFileProgressBar(++indexIntra);
						}
				}

				indexIntra = 0;
				m_intraFileProgress.Value = 0;

				StreamWriter writer = null;
				Graph graphOne,graphTwo,commonGraph;
			
				int indexInter = 0;
				bool found = false;
				foreach(Document docOne in m_documentList)
				{
					if (m_isOnlyOneFile)
					{
						if (docOne.FileName.IndexOf(m_onlyOneFileName) < 0) continue;
						else found = true;
					}
					graphOne = GraphBuilderFactory.Instance.GetInstance(m_graphRepresentation.ToString("F")).Build(docOne,m_graphSize);
					try
					{
						writer = new StreamWriter(m_outputDir + graphOne.Name + ".txt");
						foreach(Document docTwo in m_documentList)
						{
                            graphTwo = GraphBuilderFactory.Instance.GetInstance(m_graphRepresentation.ToString("F")).Build(docTwo, m_graphSize);
							commonGraph = graphOne.GetMCS(graphTwo);
							double distance = new DistMCS4VertexEdgeCount(graphOne,graphTwo).GetDistance ();
							this.WriteCommonality(writer,docOne,docTwo,graphOne,graphTwo,commonGraph,distance);
							this.SetIntraFileProgressBar(++indexIntra);
						}
						indexIntra = 0;
						this.m_intraFileProgress.Value = 0;
						if (m_isOnlyOneFile)
						{
							break;
						}
						this.SetInterFileProgressBar(++indexInter);
						if (found == false) throw new Exception("No file named " + m_onlyOneFileName + " was found");
					}
				
					catch(Exception ex)
					{
						MessageBox.Show(ex.Message);
					}
					finally
					{
						if (writer != null) writer.Close();
					}
				}
			}
			catch(Exception ex)
			{
				MessageBox.Show(ex.Message);
			}
		}

		private delegate void SetProgressBarHandler(int value);
		private void SetIntraFileProgressBar(int value)
		{
			if (m_intraFileProgress.InvokeRequired)
			{
				m_intraFileProgress.Invoke(new SetProgressBarHandler(this.SetIntraFileProgressBar),new object[]{value});
				return;
			}
			m_intraFileProgress.Value = value;
		}
		private void SetInterFileProgressBar(int value)
		{
			if (m_interFileProgress.InvokeRequired)
			{
				m_interFileProgress.Invoke(new SetProgressBarHandler(this.SetInterFileProgressBar),new object[]{value});
				return;
			}
			m_interFileProgress.Value = value;
		}

		private void WriteCommonality(StreamWriter writer,
																	Document docOne,Document docTwo,
																	Graph graphOne, Graph graphTwo, Graph commonGraph,double distance)
		{
			writer.WriteLine("===============================================================================================\n");
			writer.WriteLine(graphOne.Name + " : " + graphTwo.Name);
			writer.WriteLine("Distance : " + distance);
			this.WriteGraph(writer,graphOne.Name + " graph",docOne, graphOne);
			this.WriteGraph(writer,graphTwo.Name + " graph",docTwo, graphTwo);
			this.WriteGraph(writer,"common graph",docOne, commonGraph);

		}
		private void WriteGraph(StreamWriter writer, string title, Document document, Graph graph)
		{
			string name;
			writer.WriteLine(title);

			writer.WriteLine(graph.GetVertexCount() + " nodes");
			int i =1;
			double edgeFrequency = 0;
			int edgeCount = 0;
			double nodeFrequency = 0;
			foreach(Vertex vertex in graph.GetVertexList())
			{
				name = document.GetNodeById(vertex.GetId()).Term.ToUpper();
				writer.WriteLine(i + ". " + name + " ( " + vertex.Frequency + " ) ");
				nodeFrequency += vertex.Frequency;
				  SectionType2EdgeListMap sectionTypeMap = vertex.GetSection2EdgeMap();
						foreach(string sectionType in sectionTypeMap.Keys) 
						{
							writer.WriteLine("       -" + sectionType+"-");
							 EdgeList edgeList = sectionTypeMap[sectionType];
							  foreach(Edge edge in edgeList)
							  {
							  	writer.WriteLine("          " + document.GetNodeById(edge.GetTarget().GetId()).Term + " ( " + edge.GetFrequency() + " ) ");
									edgeFrequency += edge.GetFrequency();
									edgeCount++;
							  }
						}
				i++;
			}
			writer.WriteLine("Total edge frequency : " + edgeFrequency);
			writer.WriteLine("Total edge count : " + edgeCount);
			writer.WriteLine("Total node frequency : " + nodeFrequency);
			writer.WriteLine("Total node count : " + graph.GetVertexCount());
			writer.WriteLine("-----------------------------------------------------------------------------------------------\n");
		}
	}
}
